package com.hancher.gamelife2.backup;

import android.annotation.SuppressLint;

import com.google.gson.Gson;
import com.hancher.common.androidutil.AsyncUtils;
import com.hancher.common.androidutil.LogUtil;
import com.hancher.common.androidutil.MmkvUtil;
import com.hancher.common.androidutil.PathUtil;
import com.hancher.common.javautil.FileUtil;
import com.hancher.common.javautil.Md5Util;
import com.hancher.common.net.download.DownloadListener;
import com.hancher.gamelife2.login.BaiduLoginFragment;
import com.jeremyliao.liveeventbus.LiveEventBus;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import io.reactivex.rxjava3.functions.Consumer;
import lombok.Data;

/**
 * 描述 : 百度管理工具 <br/>
 * 时间 : 2023/12/21 19:34 <br/>
 * 作者 : Hancher ytu_shaoweijie@163.com
 */
@Data
public class BaiduNetManager {

    private static BaiduNetManager mInstance;
    public static final String BAIDU_API_UPLOAD_MESSAGE = "BAIDU_API_UPLOAD_MESSAGE";
    public static final String BAIDU_API_UPLOAD_MESSAGE_PATH = "BAIDU_API_UPLOAD_MESSAGE_PATH";
    public static final String BAIDU_API_UPLOAD_MESSAGE_FINISHED = "切片合并成功,上传完成";
    public static final String BAIDU_API_UPLOAD_AFTER_MESSAGE = "BAIDU_API_UPLOAD_AFTER_MESSAGE";
    public static final String BAIDU_API_DOWNLOAD_MESSAGE = "BAIDU_API_DOWNLOAD_MESSAGE";

    private BaiduNetManager() {

    }

    public static BaiduNetManager getInstance() {
        if (mInstance == null) {
            synchronized (BaiduNetManager.class) {
                if (mInstance == null) {
                    mInstance = new BaiduNetManager();
                }
            }
        }

        return mInstance;
    }

    //region 上传
    /**
     * 安卓本地切片目录
     */
    public static String baiduSplitDir = PathUtil.OUT_APP_CACHE + File.separator + "baidusplit" + File.separator;

    /**
     * 切片个数
     */
    int needUploadPian = 0;
    /**
     * 当前切片
     */
    int currentUploadPian = 0;
    /**
     * 备份文件
     */
    String backupFilePath;
    /**
     * 百度目标位置
     */
    String destBaiduPath;
    /**
     * 切片MD5
     */
    String filesMd5JsonStr;
    /**
     * 预上传信息
     */
    BaiduNetApi.PreUploadVO preUploadResponse;
    boolean deleteCache = false;

    /**
     * 上传文件
     * @param backupFilePath
     * @param destBaiduPath
     */
    @SuppressLint("CheckResult")
    public void uploadFile(String backupFilePath, String destBaiduPath) {
        BaiduNetManager.getInstance().setBackupFilePath(backupFilePath);
        BaiduNetManager.getInstance().setDestBaiduPath(destBaiduPath);

        AsyncUtils.run(emitter -> {
            // 1.将文件分片
            File backupFile = new File(backupFilePath);
            File pianDir = new File(baiduSplitDir);
            FileUtil.deleteFloder(baiduSplitDir);
            FileUtil.touchDir(baiduSplitDir);
            BaiduNetManager.getInstance().setNeedUploadPian(BigDecimal.valueOf(backupFile.length()).divide(BigDecimal.valueOf(4194304L), 0, RoundingMode.UP).intValue());
//            emitter.onNext("总文件大小：" + backupFile.length() + "字节, 切片个数" + BaiduNetManager.getInstance().getNeedUploadPian());
            LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                    .post("总文件大小：" + backupFile.length() + "字节, 切片个数" + BaiduNetManager.getInstance().getNeedUploadPian());

            FileInputStream fileInputStream = new FileInputStream(backupFile);
            byte[] buffer = new byte[1024];
            int byteRead;
            for (int i = 0; i < needUploadPian; i++) {
                File pianItem = new File(pianDir, i + "");
                FileOutputStream fileOutputStream = new FileOutputStream(pianItem, true);
                for (int j = 0; j < 4096; j++) {
                    byteRead = fileInputStream.read(buffer);
                    fileOutputStream.write(buffer, 0, byteRead);
                    if (byteRead < 1024) {
                        break;
                    }
                }
                fileOutputStream.flush();
                fileOutputStream.close();
                LogUtil.d("切片文件：" + pianItem.exists() + " " + pianItem.getAbsolutePath());
                LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                        .post(String.format("第%d个切片 (%b) 路径：%s", i, pianItem.exists(), pianItem.getAbsolutePath()));
            }
            fileInputStream.close();

            // 求分片文件的md5
            List<String> filesMd5 = new ArrayList<>();
            for (int i = 0; i < needUploadPian; i++) {
                filesMd5.add(Md5Util.getFileMd5(new File(pianDir, i + "")));
            }
            Gson gson = new Gson();
            String filesMd5JsonStr = gson.toJson(filesMd5);
            BaiduNetManager.getInstance().setFilesMd5JsonStr(filesMd5JsonStr);
            LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                    .post("切片md5:" + filesMd5JsonStr);

            // 2.预上传切片信息
            BaiduNetApi.PreUploadDTO resquest1 = new BaiduNetApi.PreUploadDTO()
                    .setPath(BaiduNetManager.getInstance().getDestBaiduPath())
                    .setSize(backupFile.length())
                    .setIsdir(0)
                    .setBlock_list(BaiduNetManager.getInstance().getFilesMd5JsonStr());
            BaiduNetApi.preUpload(resquest1).subscribe(result -> {
                if (result == null) {
                    LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                            .post("切片预上传请求失败");
                    return;
                }
                LogUtil.o(result);
                if (result.getErrno() != 0) {
                    LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                            .post("切片预上传失败");
                    return;
                }
                BaiduNetManager.getInstance().setPreUploadResponse(result);
                LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                        .post("切片预上传成功");

                BaiduNetManager.getInstance().setCurrentUploadPian(0);
                cyclicUpload();
            }, throwable -> {
                LogUtil.e("err:", throwable);
                LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                        .post("切片预上传失败：" + throwable);
            });
        }, (Consumer<String>) s -> {

        }, throwable -> {
            LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                    .post("切片压缩失败：" + throwable);
        });
    }

    @SuppressLint("CheckResult")
    static void cyclicUpload() {
        LogUtil.d("备份文件：" + BaiduNetManager.getInstance().getBackupFilePath());
        File backupFile = new File(BaiduNetManager.getInstance().getBackupFilePath());
        if (BaiduNetManager.getInstance().getCurrentUploadPian() >= BaiduNetManager.getInstance().getNeedUploadPian()) {
            // 4 切片整合
            BaiduNetApi.UploadFinishDTO resquest3 = new BaiduNetApi.UploadFinishDTO()
                    .setPath(BaiduNetManager.getInstance().getDestBaiduPath())
                    .setSize(backupFile.length())
                    .setIsdir(0)
                    .setRtype("3")
                    .setBlock_list(BaiduNetManager.getInstance().getFilesMd5JsonStr())
                    .setUploadid(BaiduNetManager.getInstance().getPreUploadResponse().getUploadid());
            BaiduNetApi.uploadFinish(resquest3).subscribe(preUploadResponse1 -> {
                LogUtil.o(preUploadResponse1);
                if (preUploadResponse1.getErrno() != 0) {
                    LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                            .post("切片合并失败");
                    return;
                }
                if (getInstance().isDeleteCache()) {
                    FileUtil.deleteFloder(PathUtil.OUT_APP_CACHE);
                    getInstance().setDeleteCache(false);
                }
                LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE_PATH, BaiduNetApi.UploadFinishVO.class)
                        .post(preUploadResponse1);
                LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                        .post(BAIDU_API_UPLOAD_MESSAGE_FINISHED);
            });
            return;
        }
        //  3 上传切片文件
        BaiduNetApi.UploadDTO resquest2 = new BaiduNetApi.UploadDTO()
                .setAccess_token(MmkvUtil.getString(BaiduLoginFragment.BAIDUNET_ACCESS_TOKEN, ""))
                .setPath(BaiduNetManager.getInstance().getDestBaiduPath())
                .setUploadid(BaiduNetManager.getInstance().getPreUploadResponse().getUploadid())
                .setPartseq(BaiduNetManager.getInstance().getCurrentUploadPian() + "");

        File pianDir = new File(baiduSplitDir);
        File currentPian = new File(pianDir, BaiduNetManager.getInstance().getCurrentUploadPian() + "");
        LogUtil.i("当前分片名字%s, 当前分片大小%s", currentPian.getAbsolutePath(), "" + currentPian.length());
        LogUtil.o(resquest2);
        BaiduNetApi.upload(resquest2, currentPian).subscribe(uploadResponse -> {
            LogUtil.o(uploadResponse);
            if (uploadResponse.getErrno() != 0) {
                LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                        .post("第" + BaiduNetManager.getInstance().getCurrentUploadPian() + "个切片上传失败");
                return;
            }
            LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                    .post("第" + BaiduNetManager.getInstance().getCurrentUploadPian() + "个切片上传成功");
            BaiduNetManager.getInstance().setCurrentUploadPian(BaiduNetManager.getInstance().getCurrentUploadPian() + 1);
            cyclicUpload();
        }, throwable -> {
            LiveEventBus.get(BAIDU_API_UPLOAD_MESSAGE, String.class)
                    .post("分片上传失败:" + throwable.getMessage());
        });
    }
    //endregion

    //region 下载

    /**
     * 下载文件
     * @param baiduFilePath
     * @param orginFilePath
     */
    public void downloadFile(String baiduFilePath, String orginFilePath) {
        listBdpan(baiduFilePath, orginFilePath);
    }

    /**
     * 查询列表
     */
    public void listBdpan(String baiduFilePath, String orginFilePath) {
        LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                .post(String.format("查询列表开始"));
        BaiduNetApi.ListDTO resquest = new BaiduNetApi.ListDTO()
                .setAccess_token(MmkvUtil.getString(BaiduLoginFragment.BAIDUNET_ACCESS_TOKEN, ""))
                .setDir(new File(baiduFilePath).getParent());
        BaiduNetApi.list(resquest).subscribe(listVO -> {
            for (BaiduNetApi.ListVO.Item item : listVO.getList()) {
                if (baiduFilePath.equals(item.getPath())) {
                    listInfo(baiduFilePath, orginFilePath, item);
                    return;
                }
            }
            LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                    .post(String.format("下载失败：无备份文件"));
        }, throwable -> {
            LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                    .post(String.format("下载失败：" + throwable));
        });
    }

    /**
     * 查询文件
     */
    public void listInfo(String baiduFilePath, String orginFilePath, BaiduNetApi.ListVO.Item item) {
        LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                .post(String.format("查询文件开始"));
        BaiduNetApi.ListInfoDTO resquest = new BaiduNetApi.ListInfoDTO()
                .setAccess_token(MmkvUtil.getString(BaiduLoginFragment.BAIDUNET_ACCESS_TOKEN, ""))
                .setFsids(Arrays.asList(item.getFs_id()));
        BaiduNetApi.listInfo(resquest).subscribe(listInfoVO -> {
            if (listInfoVO.getList() == null || listInfoVO.getList().size() != 1) {
                LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                        .post(String.format("下载失败：未找到文件"));
                return;
            }
            downloadRedirect(baiduFilePath, orginFilePath, item, listInfoVO.getList().get(0));
        }, throwable -> {
            LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                    .post(String.format("下载失败：" + throwable));
        });
    }

    /**
     * 下载文件
     */
    public void downloadRedirect(String baiduFilePath, String orginFilePath, BaiduNetApi.ListVO.Item item, BaiduNetApi.ListInfoVO.Item item1) {
        String newUrl = item1.getDlink() + "&access_token=" + MmkvUtil.getString(BaiduLoginFragment.BAIDUNET_ACCESS_TOKEN, "");
        File file = new File(orginFilePath);
        BaiduNetApi.download(newUrl, file.getAbsolutePath(), new DownloadListener() {
            @Override
            public void onStart() {
                LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                        .post(String.format("下载开始"));
            }

            @Override
            public void onProgress(int progress) {
                LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                        .post(String.format("下载进度" + progress));
            }

            @Override
            public void onFinish(String path) {
                LogUtil.d("下载完成：" + path);
                LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                        .post(String.format("下载完成"));
            }

            @Override
            public void onFail(String errorInfo) {
                LiveEventBus.get(BAIDU_API_DOWNLOAD_MESSAGE, String.class)
                        .post(String.format("下载失败" + errorInfo));
            }
        });
    }
    //endregion
}
